package zdream.pmfield.stage.buff.ailment;

import java.util.Arrays;
import java.util.function.Supplier;

import zdream.pmfield.data.foe.MoveAdditionalEffects;
import zdream.pmfield.data.foe.VStat;
import zdream.pmfield.stage.action.BuffAction;
import zdream.pmfield.stage.buff.foe.FoeStageBuff;
import zdream.pmfield.stage.director.AttackContext;
import zdream.pmfield.stage.director.HookType;
import zdream.pmfield.stage.director.Hooks;
import zdream.pmfield.stage.director.MoveChecker;
import zdream.pmfield.stage.director.Roll;
import zdream.pmfield.stage.message.FoeReceiveDamageMessage;
import zdream.pmfield.stage.object.FoeActor;

/**
 * <p>混乱状态
 * <p>仅攻击时, 投出的骰子中偶数个会变成其它的 {@link zdream.pmfield.data.foe.VStat}.
 * 偶数个指的是第二个 (rolls[1]), 第四个 (rolls[3])...
 * 当大失败时会攻击不仅不能命中, 还会攻击自己 (可打在护盾上).
 * <p>混乱效果能自然恢复, 3 轮之后投骰子判断是否恢复.
 * 主要通过 {@link zdream.pmfield.data.foe.VStat#LUCK} 来决定是否恢复.
 * </p>
 *
 * @author Zdream
 * @date 2023-12-11
 * @since 0.0.1
 */
public class ConfusedBuff extends FoeStageBuff {
	public static final String CATEGORY = MoveAdditionalEffects.E_CONFUSED;
	public final BuffSpan span;
	public Supplier<Boolean> buffActionCleaner;

	public ConfusedBuff(FoeActor foe) {
		super(foe);
		span = new DurationBuffSpan()
				.withMinDuration(3)
				.withStartTime(now());
	}

	@Override
	public String getCategory() {
		return CATEGORY;
	}

	@Override
	public String toString() {
		return "混乱";
	}

	@Override
	public void init() {
		preventSameBuffBeforeFoeReceiveBuff();
		onHook(HookType.BEFORE_FOE_TURN_START)
				.handle(span::checkIsNeedCured)
				.buildAndSave();
		onHook(HookType.BEFORE_ATTACK_ROLL_CHECK)
				.handle(this::randomizeRollVStat)
				.withPriority(-2000) // 比麻痹早
				.buildAndSave();
		onHook(HookType.ON_CHECK_TYPE_FIXED)
				.handle(this::checkAttackIsMiss)
				.buildAndSave();
	}

	private void randomizeRollVStat(Hooks.HookContext rawContext) {
		Hooks.AttackHookContext context = rawContext.as();
		AttackContext attackContext = context.attackContext;
		if (attackContext.attacker != target || !attackContext.isAction()) {
			return;
		}

		final Roll[] rolls = attackContext.rolls;
		if (rolls.length == 0) {
			return;
		}

		final MoveChecker moveChecker = target.stage.moveChecker;
		for (int i = 1; i < rolls.length; i += 2) {
			final Roll roll = rolls[i];

			final VStat[] vStats = Arrays.stream(VStat.values())
					.filter(vStat -> roll.vStat != vStat)
					.toArray(VStat[]::new);
			final int nextInt = moveChecker.randomInt(vStats.length);

			int checkRateFixed = rolls[i].baseValue - target.vStats[roll.vStat.ordinal()];
			rolls[i] = moveChecker.createOne(target, vStats[nextInt], checkRateFixed);
		}
	}

	private void checkAttackIsMiss(Hooks.HookContext rawContext) {
		Hooks.AttackHookContext context = rawContext.as();
		AttackContext attackContext = context.attackContext;
		if (attackContext.attacker != target) {
			return;
		}

		if (attackContext.checkPair.level != 0) {
			return;
		}

		attackContext.items.forEach(item -> item.miss = true);
		putBuffActionNow(buildTask((target.foe.level >> 2) + 1));
	}

	private static String buildTask(int damage) {
		return String.format("damage=%d", damage);
	}

	private static int parseTask(String task) {
		return Integer.parseInt(task.split("=")[1]);
	}

	@Override
	public void doTask(BuffAction action) {
		int damage = parseTask(action.task);

		final FoeReceiveDamageMessage damageMessage = new FoeReceiveDamageMessage(target)
				.withDamage(damage)
				.withTitle(CATEGORY)
				.withHpFrom(target);

		target.receiveDamage(damage);
		pushMessage(damageMessage.withHpTo(target));
	}
}
